package net.homeip.jcperera.nu.core.utils;

import java.io.IOException;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;

import net.homeip.jcperera.nu.core.CoreBase;

/**
 * Some useful methods to extract resource information
 * 
 * @name Java Resource class
 * @author julio.c.perera@gmail.com
 * @application nu
 * @since 0.1.0.0@
 */

public class ResourceUtil extends CoreBase implements Serializable
{
    // Required to implement Serializable interface
    private static final long  serialVersionUID = -4562412707572413247L;

    // CoreBase properties, for easy use from other components, as well as logging
    public static final int    runtimeLevel     = 0;
    public static final String moduleName       = "core";
    public static final String componentName    = "nu_core_utils_resource_util";

    /**
     * Obtains an URL of a Class, in order for the class to be readable using <code>java.io.File</code> functions
     * 
     * @param vclass
     *            the class
     * @return the URL pointing to the class, or <code>null</code> if the class was not found
     */
    public static URL getURLOfClass(Class<?> vclass)
    {
        String strClass = '/' + vclass.getName().replace('.', '/') + ".class";
        URL classURL = vclass.getResource(strClass);
        return classURL;
    }

    /**
     * <p>
     * Finds a resource with a given name.
     * </p>
     * <p>
     * Before delegation, an absolute resource name is constructed from the given resource name using this algorithm:
     * </p>
     * <p>
     * If the <tt>name</tt> begins with a <tt>'/'</tt> (<tt>'&#92;u002f'</tt>), then the absolute name of the resource
     * is the portion of the <tt>name</tt> following the <tt>'/'</tt>.
     * </p>
     * <p>
     * Otherwise, the absolute name is of the following form: <code>
     * modified_package_name / name
     * </code>
     * </p>
     * <p>
     * Where the <tt>modified_package_name</tt> is the package name of this provided {@link Class} with <tt>'/'</tt>
     * substituted for <tt>'.'</tt> (<tt>'&#92;u002e'</tt>). </ul>
     * </p>
     * 
     * @param vclass
     *            the {@link Class} to search the resource relative to
     * @param resourcePath
     *            the path to the resouce, usually a {@link String} specifying a file and extension
     * @return A {@link java.io.InputStream} object or <tt>null</tt> if no resource with this name is found
     */
    public static URL getURLOfResourceRelativeToClass(Class<?> vclass, String resourcePath)
    {
        resourcePath = resourcePath.trim();
        if (!resourcePath.startsWith("/"))
            resourcePath = '/' + vclass.getPackage().getName().replace('.', '/') + resourcePath;
        return vclass.getResource(resourcePath);
    }

    /**
     * <p>
     * Gets the module path from a URL, stripping the class path to the point that the URL should be pointing to the
     * base of .jar, .war or .ear in the filesystem, note that the URL could refer to a file (a compressed resource,
     * generally in a temporary deployment directory), or a directory (a uncompressed resource)
     * </p>
     * <p>
     * In any case you can refer to a file "inside" the resource, given the URL specifies an access path for accessing
     * inside these "compressed" files, using specific protocol and path information
     * </p>
     * <p>
     * <b>Note:</b> If the class is deployed expanded in the server is very important to correctly specify the
     * <code>moduleType</code> parameter as "jar", "war" or "ear", otherwise an exception or inconsistent behavior is to
     * be expected
     * </p>
     * 
     * @param url
     *            the URL to strip
     * @param moduleType
     *            the module type, it should be "jar" or "war" or "ear"
     * @return the URL without the path to the class, ending on the base of the module
     */
    public static URL getModulePathFromURL(URL url, String moduleType) throws MalformedURLException
    {
        String prefix = "";
        String suffix = "";
        if (url.getProtocol() == "file") suffix = "." + moduleType.toLowerCase() + "/";
        else suffix = "!/";
        prefix = url.toExternalForm();
        prefix = prefix.substring(0, prefix.lastIndexOf(suffix) + suffix.length());
        URL result;
        result = new URL(prefix);
        return result;
    }

    /**
     * <p>
     * Gets the module path from a Class, stripping the class path to the point that the URL should be pointing to the
     * base of .jar, .war or .ear in the filesystem, note that the URL could refer to a file (a compressed resource,
     * generally in a temporary deployment directory), or a directory (a uncompressed resource)
     * </p>
     * <p>
     * In any case you can refer to a file "inside" the resource, given the URL specifies an access path for accessing
     * inside these "compressed" files, using specific protocol and path information
     * </p>
     * <p>
     * <b>Note:</b> If the class is deployed expanded in the server is very important to correctly specify the
     * <code>moduleType</code> parameter as "jar", "war" or "ear", otherwise an exception or inconsistent behavior is to
     * be expected
     * </p>
     * 
     * @param vclass
     *            the Class
     * @param moduleType
     *            the module type, it should be "jar" or "war" or "ear"
     * @return the URL without the path to the class, ending on the base of the module
     */
    public static URL getModulePathFromClass(Class<Object> vclass, String moduleType) throws MalformedURLException
    {
        return getModulePathFromURL(getURLOfClass(vclass), moduleType);
    }

    /**
     * Gets the Context ClassLoader associated with the current thread
     * 
     * @return the ClassLoader
     */
    private static ClassLoader getContextClassLoaderFromCurrentThread()
    {
        return Thread.currentThread().getContextClassLoader();
    }

    /**
     * Gets the ClassLoader associated with the current class
     * 
     * @return the ClassLoader
     */
    @SuppressWarnings("unused")
    private static ClassLoader getClassLoaderFromCurrentClass()
    {
        return ResourceUtil.class.getClassLoader();
    }

    /**
     * Gets all the resource URLs associated with a given resource specified by its path relative to the root of any
     * .jar file or directory associated with this deployed project, it could return more than one URL in case the
     * specified resource is to be found in one than more context inside the EAR.
     * 
     * @param resourceName
     *            the resource (example: META-INF/application.xml)
     * @return the Enumeration of URLs pointing to each one of these resources
     * @throws IOException
     *             in case something goes wrong
     */
    public static Enumeration<URL> getURLsFromResourceNameString(String resourceName) throws IOException
    {
        return getContextClassLoaderFromCurrentThread().getResources(resourceName);
    }

    /**
     * Gets the resource URL associated with a given resource specified by its path relative to current classloader.
     * 
     * @param resourceName
     *            the resource (example: META-INF/application.xml)
     * @return the URL pointing to the resource
     * @throws IOException
     *             in case something goes wrong
     */
    public static URL getURLfromResourceName(String resourceName) throws IOException
    {
        return getContextClassLoaderFromCurrentThread().getResource(resourceName);
    }

}
